package cn.tedu.peipei.base.handler;

import cn.tedu.peipei.base.enums.StatusCode;
import cn.tedu.peipei.base.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import springfox.documentation.spring.web.json.Json;

import javax.validation.ConstraintViolationException;

/**
 * ControllerAdvice注解：标识当前的类为全局异常处理器类型；可以处理由控制器抛出的异常
 * 1 如果Controller中抛出了异常，首先看是否定义了全局异常处理器；
 * 2如果定义了会在全局异常处理器中找对应的异常处理方法；
 * 3如果找到了对应的异常处理方法，则执行异常处理方法中的代码逻辑
 * RestControllerAdvice注解：复合注解，相当于@ResponseBody+@ControllerAdvise注解
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    /*
    ExceptionHandler注解：表示方法为具体的异常处理方法；需要一个异常处理类型的形式参数；
    1优先查找该控制器异常对应的异常处理方法；
    2如果没有对应的异常处理方法，则会找父类的异常处理方法；
    3如果没有父类的异常处理方法，则会走SpringMVC自己的异常处理机制；
     */
    /**
     * 处理业务层异常
     * ExceptionHandler注解；表示此方法为异常处理方法
     *
     * @param ex 异常对象
     * @return
     */
    @ExceptionHandler
    public JsonResult doHandleServiceException(ServiceException ex){
        //如果出现了业务层异常，打印错误日志，显示当前错误状态码的描述信息
        //如：ServiceException:用户名已被占用
        log.error("ServiceException:"+ex.getStatusCode().getMsg());
        //将错误状态码返回前端
        return new JsonResult(ex.getStatusCode());
    }
    /**
     * 第一个异常处理方法：IllegalArgumentException
     *
     * @Param ex 异常对象
     * @return JsonResult
     */
    @ExceptionHandler
    public JsonResult doHandleIllegalArgumentException(IllegalArgumentException ex){
        //获取异常提示消息：ex.getMessage()[微博ID值无效]
        String message =ex.getMessage();
        log.error("IllegalArgumentException:"+message);
        return new JsonResult(StatusCode.OPERATION_FAILED,message);
    }
    /**
     * 第二个异常处理方法：RuntimeException
     *
     * @param ex 异常处理对象
     * @return JsonResult
     */
    @ExceptionHandler
    public JsonResult doHandleRuntimeException(RuntimeException ex){
        String message =ex.getMessage();
        log.debug("RuntimeException:"+message);
        return new JsonResult(StatusCode.OPERATION_FAILED,message);
    }
    /**
     * 第三个异常处理方法：Method、ArgumentNotValidException
     * 专门处理pojo类型校验抛出1的异常
     * 1String Validation 框架抛出；
     * 2校验POJO类属性时，参数未满足要求
     */
    @ExceptionHandler
    public JsonResult doHandleMethodArgumentNotValidException(MethodArgumentNotValidException ex){
        //Validation中，验证POJO类型参数获取提示消息使用：ex.getFieldError().getDefaultMessage()方法。
        String message =ex.getFieldError().getDefaultMessage();
        log.error("MethodArgumentNotValidException:"+message);
        return new JsonResult(StatusCode.VALIDATE_ERROR,message);
    }

    /**
     * 第四个异常处理方法：ConstraintViolationException
     * 专门处理声明参数方式验证框架校验抛出的异常
     * 1 Spring Validation框架抛出
     * 2 声明参数方式接受数据检验时，参数未满足要求
     * @param ex
     * @return
     */
    @ExceptionHandler
    public JsonResult doHandleConstraintViolationException(ConstraintViolationException ex){
        //selectById.id:微博ID必须在200~500之间
        String message =ex.getMessage().split(":")[1].trim();
        log.error("ConstraintViolationException:"+message);
        return new JsonResult(StatusCode.VALIDATE_ERROR);
    }

}
